package com.xmlt.ui.builder.generator;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Display;

import com.xmlt.core.template.TemplateException;
import com.xmlt.core.template.TemplateManager;
import com.xmlt.core.template.generation.GenerationTemplate;
import com.xmlt.core.template.generation.IGenerationDescriptor;
import com.xmlt.core.template.instance.Instance;
import com.xmlt.ui.builder.BuilderPlugin;

public class FileGenerationBuilder extends IncrementalProjectBuilder {
	public static final String BUILDER_ID = "com.xmlt.ui.builder.generator.FileGenerationBuilder";
	
	
	private TemplateManager manager;
	public FileGenerationBuilder() {
	}
	
	public FileGenerationBuilder(TemplateManager tm) {
		manager = tm;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.core.internal.events.InternalBuilder#build(int,
	 *      java.util.Map, org.eclipse.core.runtime.IProgressMonitor)
	 */
	protected IProject[] build(int kind, @SuppressWarnings("rawtypes") Map args, IProgressMonitor monitor)
			throws CoreException {
		manager = BuilderPlugin.getTemplateManager(getProject());
		//fullBuild(monitor);
		if (kind == FULL_BUILD) {
		} else {
			/*IResourceDelta delta = getDelta(getProject());
			if (delta == null) {
				fullBuild(monitor);
			} else {
				incrementalBuild(delta, monitor);
			}*/
		}
		return null;
	}

	void handleDeletedResource(IResource resource) {
	}
	
	void checkResource(IResource resource) throws CoreException {
		IFile file = (IFile) resource.getAdapter(IFile.class);
		if (file == null)
			return;
			
		String ref = file.getProjectRelativePath().toString();
		InstanceVisitor instanceVisitor = new InstanceVisitor();
		getProject().accept(instanceVisitor);
		if (resource.getName().endsWith(".gtmpl")) {
			try {
				GenerationTemplate gt = manager.findGenerationTemplate(ref);
				List<Instance> instances = instanceVisitor.getInstances();
				List<IGenerationDescriptor> generationDescriptors = new ArrayList<IGenerationDescriptor>();
				for (Instance ins: instances) {
					generationDescriptors.addAll(gt.getDescriptorsForInstance(ins));
				}

				//IContainer container = file.getParent();
				for (IGenerationDescriptor gd: generationDescriptors) {
					generateFile(gd);
				}
			} catch(Exception rte) {
				MessageDialog.openError(Display.getDefault().getActiveShell(), "Error while generating files", rte.getMessage());
			}
		}
	}

	protected void fullBuild(final IProgressMonitor monitor)
			throws CoreException {
		try {
			getProject().accept(new ResourceVisitor());
		} catch (CoreException e) {
		}
	}

	protected void incrementalBuild(IResourceDelta delta,
			IProgressMonitor monitor) throws CoreException {
		getProject().accept(new ResourceVisitor());
	}
	
	private void generateFile(IGenerationDescriptor descriptor) throws FileGenerationException {
		try {
			IResource targetFileResource = getProject().getFile(descriptor.getPath() + "/" + descriptor.getFileName());
			IFile targetFile = (IFile) targetFileResource.getAdapter(IFile.class);
			
			SectionElementVisitor visitor = new SectionElementVisitor(descriptor.getInstance());
			descriptor.getGeneratingSection().accept(visitor);
			String contents = visitor.getString();
			InputStream contentStream = new ByteArrayInputStream(contents.getBytes());
			if (targetFile.exists()) {
				targetFile.setContents(contentStream, true, true, null);
			} else {
				targetFile.create(contentStream, true, null);
			}
		} catch (TemplateException e) {
			throw new FileGenerationException(e);
		} catch (CoreException e) {
			throw new FileGenerationException(e);
		}
		
	}
	
	class ResourceVisitor implements IResourceVisitor {
		public boolean visit(IResource resource) {
			try {
				checkResource(resource);
			} catch (CoreException e) {
				MessageDialog.openError(Display.getDefault().getActiveShell(), "Error while generating files", e.getMessage());
				return false;
			}
			return true;
		}
	}
	
	class InstanceVisitor implements IResourceVisitor {
		private List<Instance> instances = new ArrayList<Instance>();
		
		public boolean visit(IResource resource) {
			if (resource.getName().endsWith(".inst")) {
				IFile file = (IFile) resource.getAdapter(IFile.class);
				try {
					Instance ins = manager.loadInstance(file.getProjectRelativePath().toString());
					instances.add(ins);
				} catch (TemplateException e) {
				}
			}
			return true;
		}
		
		public List<Instance> getInstances() {
			return instances;
		}
	}
}
